package br.com.ctm.advogadope.mobile.bean;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.enterprise.context.ConversationScoped;
import javax.inject.Inject;
import javax.inject.Named;
import javax.persistence.PersistenceException;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;

import org.apache.commons.lang.exception.ExceptionUtils;

import br.com.ctm.advogadope.dao.api.ProcessoDao;
import br.com.ctm.advogadope.model.Advogado;
import br.com.ctm.advogadope.model.AdvogadoNotificacao;
import br.com.ctm.advogadope.model.Processo;
import br.com.ctm.advogadope.model.Tribunal;
import br.com.ctm.advogadope.model.Tribunal.TipoJuizo;
import br.com.ctm.advogadope.model.Usuario;
import br.com.ctm.advogadope.negocio.api.AdvogadoNegocio;
import br.com.ctm.advogadope.negocio.api.AdvogadoNotificacaoNegocio;
import br.com.ctm.advogadope.negocio.api.ProcessoNegocio;
import br.com.ctm.advogadope.negocio.api.TribunalNegocio;
import br.com.ctm.advogadope.negocio.api.UfNegocio;
import br.com.framework.apresentacao.bean.CRUDBean;
import br.com.framework.negocio.exception.NegocioException;
import br.com.framework.persistencia.sort.Order;
import br.jus.cnj.intercomunicacao.beans.ProcessoJudicial;

@Named
@ConversationScoped
public class ProcessoMobileBean extends CRUDBean<Processo, ProcessoDao, ProcessoNegocio> {

	private static final String PM_PROCESSO_EDIT = "pm:processoEdit";

	private static final String PM_PROCESSO_LIST = "pm:processoList";

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	@Inject
	private UfNegocio ufNegocio;
	@Inject
	private TribunalNegocio tribunalNegocio;
	@Inject
	private LoginMobileBean loginBean;
	@Inject
	private AdvogadoNegocio advogadoNegocio;
	@Inject
	private AppConfigurationMobileBean configBean;
	@Inject
	private AdvogadoNotificacaoNegocio cliNotifNegocio;
	
	private List<Tribunal> tribunais;
	
	private List<AdvogadoNotificacao> notificacoes;
	
	private AdvogadoNotificacao notificacao;
	
	private ProcessoJudicial processoJudicial;
	
	private Tribunal fTribunal;
	private TipoJuizo fTipoJuizo;
	private String fNpu;
	
	private List<TipoJuizo> tipoJuizoList = new ArrayList<TipoJuizo>();
	
	public ProcessoMobileBean() {
		tipoJuizoList.add(TipoJuizo.PRIMEIRO_GRAU);
		tipoJuizoList.add(TipoJuizo.SEGUNDO_GRAU);
	}

	@Inject
	protected void setNegocio(ProcessoNegocio negocio) {
		super.setNegocio(negocio);
	}

	/**
	 * @return the tipoJuizoList
	 */
	public List<TipoJuizo> getTipoJuizoList() {
		return tipoJuizoList;
	}

	/**
	 * @param tipoJuizoList the tipoJuizoList to set
	 */
	public void setTipoJuizoList(List<TipoJuizo> tipoJuizoList) {
		this.tipoJuizoList = tipoJuizoList;
	}

	/**
	 * @return the notificacao
	 */
	public AdvogadoNotificacao getNotificacao() {
		return notificacao;
	}

	/**
	 * @param notificacao the notificacao to set
	 */
	public void setNotificacao(AdvogadoNotificacao notificacao) {
		this.notificacao = notificacao;
	}

	public ProcessoJudicial getProcessoJudicial() {
		return processoJudicial;
	}

	public void setProcessoJudicial(ProcessoJudicial processoJudicial) {
		this.processoJudicial = processoJudicial;
	}

	public List<Tribunal> getTribunais() {
		return tribunais;
	}

	public void setTribunais(List<Tribunal> tribunais) {
		this.tribunais = tribunais;
	}
	
	/**
	 * @return the notificacoes
	 */
	public List<AdvogadoNotificacao> getNotificacoes() {
		return notificacoes;
	}

	/**
	 * @param notificacoes the notificacoes to set
	 */
	public void setNotificacoes(List<AdvogadoNotificacao> notificacoes) {
		this.notificacoes = notificacoes;
	}

	@Override
	protected void beforeOutcomeCreate() {
		Tribunal tEx = new Tribunal();
		tEx.setUf(ufNegocio.findBySigla(configBean.getProperty("mobile.uf")));
		tribunais = tribunalNegocio.findByExample(tEx, "sigla", Order.ASCENDING);
	}
	
	@Override
	protected void beforeOutcomeEdit() {
		beforeOutcomeCreate();
	}
	
	public Tribunal getfTribunal() {
		return fTribunal;
	}

	public void setfTribunal(Tribunal fTribunal) {
		this.fTribunal = fTribunal;
	}

	/**
	 * @return the fTipoJuizo
	 */
	public TipoJuizo getfTipoJuizo() {
		return fTipoJuizo;
	}

	/**
	 * @param fTipoJuizo the fTipoJuizo to set
	 */
	public void setfTipoJuizo(TipoJuizo fTipoJuizo) {
		this.fTipoJuizo = fTipoJuizo;
	}

	public String getfNpu() {
		return fNpu;
	}

	public void setfNpu(String fNpu) {
		this.fNpu = fNpu;
	}

	public void beforeOutcomeSearch() {
		initConversation();
		beforeOutcomeCreate();
	}
	
	@Override
	public String criar() {
		super.criar();
		return PM_PROCESSO_EDIT;
	}
	
	public String visualizar() {
		String outcome = PM_PROCESSO_LIST;
		if (getEntidade() != null) {
			try {
				this.processoJudicial = getNegocio().buscarProcessoJudicial(getEntidade().getId(), true, null);
				outcome = "processo" + PARAM_FACES_REDIRECT_TRUE;
			} catch (NegocioException e) {
				LOGGER.error("Nao foi possível obter informações do processo: " 
						+ getEntidade().getNpu(), e);
				this.facesMessages.addMessageError(null, e.getMessage());
			}
		}
		return outcome; 
	}
	
	public String visualizarNotificacao() {
		try {
			cliNotifNegocio.remove(notificacao);
		} catch (PersistenceException e) {
			LOGGER.error("Falha ao remover a notificacao id: " + notificacao.getId(), e);
		} catch (NegocioException e) {
			LOGGER.error("Erro de negocio ao remover a notificacao id: " + notificacao.getId(), e);
		}
		return visualizar(); 
	}
	
	@Override
	public String cancelar() {
		return PM_PROCESSO_LIST;
	}
	
	@Override
	public String editar() {
		super.editar();
		return PM_PROCESSO_EDIT;
	}
	
	/**
	 * 
	 */
	public void carregarNotificacoes() {
		this.notificacoes = cliNotifNegocio.findByAdvogado(getAdvogado());
	}
	
	@Override
	public void loadDataModel() {
		this.getEntidadeList().clear();
		if (loginBean.getUsuario() != null) {
			if (loginBean.getUsuario().getAdvogado() != null) {
				this.getEntidadeList().addAll(getNegocio().findByAdvogado(
					loginBean.getUsuario().getAdvogado(), -1, -1, true));
			} else {
				getFacesMessages().addMessageError(null, "processo.erro.usuarioNaoPossuiAdvogado");
			}
		} else {
			getFacesMessages().addMessageError(null, "processo.erro.usuarioNaoEncontrado");
		}
	}
	
	@Override
	public String salvar() {
		if (isManaged()) {
			LOGGER.debug("Salvando entidade existente: " + getEntidadeClassName());
			try {
				getNegocio().update(getEntidade());
			} catch (PersistenceException e) {
				getFacesMessages().addMessageError(null, "processo.erro.persistencia.editar");
				LOGGER.error("Falha de persistência ao editar entidade " 
						+ getEntidadeClassName(), e);
			} catch (NegocioException e) {
				getFacesMessages().addMessageError(null, e.getMessage());
				LOGGER.error("Falha de negocio ao editar entidade " 
						+ getEntidadeClassName(), e);
			} catch (Exception e) {
				Throwable rootCause = ExceptionUtils.getRootCause(e);
				if (rootCause instanceof ConstraintViolationException) {
					Iterator<ConstraintViolation<?>> constraintIt = 
							((ConstraintViolationException)rootCause).getConstraintViolations().iterator();
					while (constraintIt.hasNext()) {
						ConstraintViolation<?> violation = constraintIt.next();
						getFacesMessages().addMessageError(violation.getPropertyPath().toString(), violation.getMessage());
					}
				} else {
					LOGGER.error("Erro ao editar entidade " 
							+ getEntidadeClassName(), e);
					getFacesMessages().addMessageError(null, rootCause.getMessage());
				}
				return null;
			}
		} else {
			LOGGER.debug("Salvando nova entidade: " + getEntidadeClassName());
			try {
				getNegocio().insert(getEntidade());
			} catch (PersistenceException e) {
				getFacesMessages().addMessageError(null, "processo.erro.persistencia.inserir");
				LOGGER.error("Falha de persistência ao inserir entidade " 
						+ getEntidadeClassName(), e);
			} catch (NegocioException e) {
				getFacesMessages().addMessageError(null, e.getMessage());
				LOGGER.error("Falha de negocio ao inserir entidade " 
						+ getEntidadeClassName(), e);
			} catch (Exception e) {
				Throwable rootCause = ExceptionUtils.getRootCause(e);
				if (rootCause != null && rootCause instanceof ConstraintViolationException) {
					Iterator<ConstraintViolation<?>> constraintIt = 
							((ConstraintViolationException)rootCause).getConstraintViolations().iterator();
					while (constraintIt.hasNext()) {
						ConstraintViolation<?> violation = constraintIt.next();
						getFacesMessages().addMessageError(violation.getPropertyPath().toString(), violation.getMessage());
					}
				} else {
					LOGGER.error("Erro ao inserir entidade " 
							+ getEntidadeClassName(), e);
					getFacesMessages().addMessageError(null, rootCause.getMessage());
				}
				return null;
			}
		}
		
		Usuario usuario = loginBean.getUsuario();
		Advogado advogado = usuario.getAdvogado();
		if (advogado != null) {
			advogado.addProcesso(getEntidade());
			try {
				advogadoNegocio.update(advogado);
				conversation.end();
			} catch (PersistenceException e) {
				getFacesMessages().addMessageError(null, "advogado.erro.persistencia.editar");
				LOGGER.error("Falha de persistência ao editar entidade advogado.", e);
			} catch (NegocioException e) {
				getFacesMessages().addMessageError(null, e.getMessage());
				LOGGER.error("Falha de negocio ao editar advogado.", e);
			} catch (Exception e) {
				Throwable rootCause = ExceptionUtils.getRootCause(e);
				if (rootCause instanceof ConstraintViolationException) {
					Iterator<ConstraintViolation<?>> constraintIt = 
							((ConstraintViolationException)rootCause).getConstraintViolations().iterator();
					while (constraintIt.hasNext()) {
						ConstraintViolation<?> violation = constraintIt.next();
						getFacesMessages().addMessageError(violation.getPropertyPath().toString(), violation.getMessage());
					}
				} else {
					LOGGER.error("Erro ao editar entidade advogado" , e);
					getFacesMessages().addMessageError(null, rootCause.getMessage());
				}
				return null;
			}
		}
		return PM_PROCESSO_LIST;
	}
	
	/**
	 * @return
	 */
	public Advogado getAdvogado() {
		Advogado advogado = null;
		Usuario usuario = loginBean.getUsuario();
		if (usuario != null) {
			if (usuario.getAdvogado() != null) {
				advogado = usuario.getAdvogado();
			} else {
				getFacesMessages().addMessageError(null, "processo.erro.usuarioNaoPossuiAdvogado");
			}
		} else {
			getFacesMessages().addMessageError(null, "processo.erro.usuarioNaoEncontrado");
		}
		return advogado;
	}
	
	/**
	 * @return
	 */
	public String pesquisar() {
		this.getEntidadeList().clear();
		Advogado advogado = getAdvogado();
		if (advogado != null) {
			Processo filtro = new Processo();
			filtro.setNpu(fNpu);
			filtro.setTipoJuizo(fTipoJuizo);
			filtro.setTribunal(fTribunal);
			List<Processo> list = getNegocio().findByFiltroEAdvogado(filtro, advogado, -1, -1, true);
			this.getEntidadeList().addAll(list);
		}
		return "pm:resultadoView";
	}
}
